package com.mas.user;

import com.mas.common.AgentUtil;
import com.mas.common.Consts;
import com.mas.resource.ResourceInfo;
import com.mas.session.Session;
import com.mas.session.state.ExitState;
import com.mas.session.state.FailureExit;
import com.mas.session.state.NewProposalProcessor;
import com.mas.strategey.Proposal;
import com.thoughtworks.xstream.XStream;

import jade.core.AID;
import jade.core.behaviours.Behaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

@SuppressWarnings("serial")
public class UserAgentSessionBehaviour extends Behaviour {

	private Session session;
	private AID monitorAgentID;
	private Proposal proposal;

	private Consts.InternalState internalState;
	private MessageTemplate messageTemplate;

	public UserAgentSessionBehaviour(Session session, AID monitorAgentID,
			Proposal proposal) {
		super();
		this.session = session;
		this.monitorAgentID = monitorAgentID;
		this.proposal = proposal;
		internalState = Consts.InternalState.SEND_CFP;
	}

	public void action() {

		if (internalState == Consts.InternalState.SEND_CFP) {
			sendCFP();

			internalState = Consts.InternalState.RECIEVE_MSG;
		} else if (internalState == Consts.InternalState.RECIEVE_MSG) {
			ACLMessage replyMsg = myAgent.receive(messageTemplate);
			if (replyMsg == null) {
				block();
			} else {
				processReply(replyMsg);
				internalState = Consts.InternalState.DONE;
			}
		} else if (internalState == Consts.InternalState.DONE) {
			// do nothing
			AgentUtil.logInfo(myAgent,"internalState ==Consts.InternalState.DONE");
			block();
		}

	}

	private void sendCFP() {
		ACLMessage message = new ACLMessage(ACLMessage.CFP);
		message.addReceiver(monitorAgentID);
		message.setConversationId(session.buildUniqueID());
		
		XStream xstream = new XStream();
		String content = xstream.toXML(proposal);
		message.setContent(content);

		AgentUtil.logInfo(session, "sending CFP");

		myAgent.send(message);

		messageTemplate = MessageTemplate.or(MessageTemplate
				.MatchPerformative(ACLMessage.REFUSE), MessageTemplate
				.MatchPerformative(ACLMessage.PROPOSE));

		messageTemplate = MessageTemplate.and(MessageTemplate
				.MatchConversationId(session.buildUniqueID()), messageTemplate);
	}

	

	private void processReply(ACLMessage replyMsg) {
		if (replyMsg.getPerformative() == ACLMessage.REFUSE) {
			AgentUtil.logInfo(session,
					"Monitor refuse for this proposal, exiting...");
			moveToExitState(replyMsg, "Monitor refuse for this proposal");

		} else if (replyMsg.getPerformative() == ACLMessage.PROPOSE) {
			AgentUtil.logInfo(session, "reading proposal...");

			proposal = AgentUtil.readProposal(replyMsg.getContent());
			if (proposal == null) {
				moveToFailureState(replyMsg);
			} else {
				try {
					NewProposalProcessor state = (NewProposalProcessor) session
							.assignState(NewProposalProcessor.class.getName());
					state.setProposal(proposal);
					session.setCurrentState(state);
					session.processNewProposal(replyMsg);
				} catch (Exception e) {
					AgentUtil
							.logInfo(session, "Fatal Error occure, exiting...");
					e.printStackTrace();
					moveToExitState(replyMsg, "Fatal Error occure");
					((UserResourceAgent) myAgent)
							.displyError("Fatal Error occure, exiting...");
				}
			}

		}
	}

	public boolean done() {
		if (!session.isAliveInd()) {
			if (session.isAccepted()) {
				Proposal proposal = session.getCurrentState().getProposal();
				((UserResourceAgent) this.myAgent)
						.displyMsg("There is a deal\n\n"
								+ createProposalStr(proposal));
			} else {
				((UserResourceAgent) this.myAgent)
						.displyMsg("Sorry, there is No deal...\n\n"+
								session.getExitReason());
			}
			return true;
		}
		return false;
	}

	private String createProposalStr(Proposal proposal) {
		StringBuffer buffer = new StringBuffer();

		buffer.append("Proposal Infromation:\n");
		for (int i = 0; i < proposal.getResourceInfos().length; i++) {
			ResourceInfo resourceInfo = proposal.getResourceInfos()[i];

			buffer.append(resourceInfo.getResourceName() + " : "
					+ resourceInfo.getRequiredUsage());
			buffer.append("\n");
		}
		buffer.append("\n");
		buffer.append("Total Price aggreed : " + proposal.getPrice());

		return buffer.toString();
	}

	private void moveToExitState(ACLMessage message, String reasoneMsg) {
		ExitState state = (ExitState) session.assignState(ExitState.class
				.getName());
		session.setCurrentState(state);
		state.exit(message, reasoneMsg);
	}

	private void moveToFailureState(ACLMessage message) {
		FailureExit state = (FailureExit) session.assignState(FailureExit.class
				.getName());
		session.setCurrentState(state);
		state.notUnderstandMsgContent(message, "Expecting Proposal Object");
	}

}
